module ctrl_center
(
	input wire sys_clk,
	input wire sys_rst_n,
	
	input wire init_done,
	input wire decode_done,
	input wire [4:0] op_code_in,
	input wire [2:0] reserve_bit_in,
	input wire [7:0] op_rand_in,
	
	inout wire [15:0] ctrl_bus,
	inout wire [15:0] addr_bus,
	inout wire [15:0] data_bus,
	
	inout wire [15:0] ctrl_sig_inner,
	inout wire [15:0] addr_sig_inner,
	inout wire [15:0] data_sig_inner,
	
	output reg work_ok,
	inout wire work_ok_inner,

	output wire [15:0] oprand0,
	output wire [15:0] oprand1,
	output wire [15:0] oprand2,
	
	output reg [15:0] ip,	//instruction pointer
	output reg get_inst_en,
	output reg exe_en,
	output reg [4:0] op_code_out,
	output reg [2:0] reserve_bit_out,
	output reg [7:0] op_rand_out,
	
	inout wire job_ok
);

/*********************************************
ctrl_sig_inner[0]:register write enable：寄存器写使能
ctrl_sig_inner[1]:register read enable：寄存器读使能
ctrl_sig_inner[2]:random memory write ebable：内存写使能
ctrl_sig_inner[3]:random memory read enable：内存读使能
ctrl_sig_inner[4]:Arithmetic and Logic calculate：算术逻辑运算
ctrl_sig_inner[5]:reserve：保留
ctrl_sig_inner[6]:reserve：保留
ctrl_sig_inner[7]:reserve：保留
ctrl_sig_inner[8]:reserve：保留
ctrl_sig_inner[9]:reserve：保留
ctrl_sig_inner[10]:reserve：保留
ctrl_sig_inner[11]:reserve：保留
ctrl_sig_inner[12]:reserve：保留
ctrl_sig_inner[13]:reserve：保留
ctrl_sig_inner[14]:reserve：保留
ctrl_sig_inner[15]:reserve：保留
还有一种运算叫做读取立即数，将立即数放入内部寄存器。
此运算不需要通过内部信号的参与。
************************************************/

reg work_ok_d1;
reg work_ok_d2;
reg exe_running;
reg job_ok_d1;
reg job_ok_d2;

reg [15:0] inner_reg[3:0];
reg [15:0] ctrl_bus_buf;
reg [15:0] addr_bus_buf;
reg [15:0] data_bus_buf;
reg [1:0] ctrl_bus_index;

reg [15:0] ctrl_bus_represent;
reg [15:0] addr_bus_represent;
reg [15:0] data_bus_represent;

reg [15:0] ctrl_bus_dly;

reg reg_write_flag;
reg reg_write_flag_d1;
reg reg_write_flag_d2;

reg reg_read_flag;
reg reg_read_flag_d1;
reg reg_read_flag_d2;

reg ram_write_flag;
reg ram_write_flag_d1;
reg ram_write_flag_d2;

reg ram_read_flag;
reg ram_read_flag_d1;
reg ram_read_flag_d2;

reg imd_read_flag;  //immediate data read
reg imd_read_flag_d1;
reg imd_read_flag_d2;

reg ALU_flag;
reg ALU_flag_d1;
reg ALU_flag_d2;

reg ip_update_flag;
reg ip_update_flag_d1;
reg ip_update_flag_d2;

reg stop_flag;
reg stop_flag_d1;
reg stop_flag_d2;

/********************************************
	对于指令指针寄存器ip的更新，我将其设置为，
直接在本模块来实施。我将其控制总线的信号值设置
为24到27。其中，24表示将ip加上当时执行的指令的
长度，以指向下一条指令。当前，我设计的这个入门
型处理器的指令长度固定为2字节。然而，我在为ram
和ram_disk建模的时候，一个单元就是2字节。所以，
后文在更新指令指针寄存器ip的时候，每次只是加1.
	25表示将ip寄存器加上一个数，这个数值由数据总线
传来。
	26表示将ip寄存器设置为某一个数值。这个数值同样
由数据总线传来。
27表示将ip寄存器复位为0。
*********************************************/

wire new_task;

assign ctrl_sig_inner = ctrl_bus_represent;
assign addr_sig_inner = addr_bus_represent;
assign data_sig_inner = data_bus_represent;
assign new_task = (ctrl_bus < 16'hffff && ctrl_bus_dly == 16'hffff) ? 1'b1 : 1'b0;

assign oprand0 = inner_reg[0];
assign oprand1 = inner_reg[1];
assign oprand2 = inner_reg[2];

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		ctrl_bus_dly <= 16'hz;
	else
		ctrl_bus_dly <= ctrl_bus;

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		work_ok_d1 <= 1'b0;
		work_ok_d2 <= 1'b0;
	end
	else
	begin
		work_ok_d1 <= work_ok;
		work_ok_d2 <= work_ok_d1;
	end

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		job_ok_d1 <= 1'b0;
		job_ok_d2 <= 1'b0;
	end
	else
	begin
		job_ok_d1 <= job_ok;
		job_ok_d2 <= job_ok_d1;
	end

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		exe_running <= 1'b0;
	else if (init_done == 1'b1)
		exe_running <= 1'b1;
	else if (stop_flag == 1'b1)
		exe_running <= 1'b0;
	else
		exe_running <= exe_running;

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		get_inst_en <= 1'b0;
	else if (init_done == 1'b1)
		get_inst_en <= 1'b1;
	else if (job_ok_d1 == 1'b1 && exe_running == 1'b1)
		get_inst_en <= 1'b1;
	else
		get_inst_en <= 1'b0;

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		exe_en <= 1'b0;
		op_code_out <= 5'h0;
		reserve_bit_out <= 3'h0;
		op_rand_out <= 8'h0;
	end
	else if (decode_done == 1'b1)
	begin
		exe_en <= 1'b1;
		op_code_out <= op_code_in;
		reserve_bit_out <= reserve_bit_in;
		op_rand_out <= op_rand_in;
	end
	else
	begin
		exe_en <= 1'b0;
		op_code_out <= op_code_out;
		reserve_bit_out <= reserve_bit_out;
		op_rand_out <= op_rand_out;
	end

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		ctrl_bus_buf <= 16'hz;
		addr_bus_buf <= 16'hz;
		data_bus_buf <= 16'hz;
		ctrl_bus_index <= 2'hz;
	end
	else if (new_task == 1'b1)
	begin
		ctrl_bus_buf <= ctrl_bus;
		addr_bus_buf <= addr_bus;
		data_bus_buf <= data_bus;
		ctrl_bus_index <= ctrl_bus[1:0];
	end
	else
	begin
		ctrl_bus_buf <= ctrl_bus_buf;
		addr_bus_buf <= addr_bus_buf;
		data_bus_buf <= data_bus_buf;
		ctrl_bus_index <= ctrl_bus_index;
	end

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		reg_write_flag <= 1'b0;
	else if ((new_task == 1'b1) && (ctrl_bus >= 16'd0) && (ctrl_bus < 16'd4))
		reg_write_flag <= 1'b1;
	else
		reg_write_flag <= 1'b0;

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		reg_write_flag_d1 <= 1'b0;
		reg_write_flag_d2 <= 1'b0;
	end
	else
	begin
		reg_write_flag_d1 <= reg_write_flag;
		reg_write_flag_d2 <= reg_write_flag_d1;
	end

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		reg_read_flag <= 1'b0;
	else if ((new_task == 1'b1) && (ctrl_bus >= 16'd4) && (ctrl_bus < 16'd8))
		reg_read_flag <= 1'b1;
	else
		reg_read_flag <= 1'b0;

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		reg_read_flag_d1 <= 1'b0;
		reg_read_flag_d2 <= 1'b0;
	end
	else
	begin
		reg_read_flag_d1 <= reg_read_flag;
		reg_read_flag_d2 <= reg_read_flag_d1;
	end

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		ram_write_flag <= 1'b0;
	else if ((new_task == 1'b1) && (ctrl_bus >= 16'd8) && (ctrl_bus < 16'd12))
		ram_write_flag <= 1'b1;
	else
		ram_write_flag <= 1'b0;

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		ram_write_flag_d1 <= 1'b0;
		ram_write_flag_d2 <= 1'b0;
	end
	else
	begin
		ram_write_flag_d1 <= ram_write_flag;
		ram_write_flag_d2 <= ram_write_flag_d1;
	end

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		ram_read_flag <= 1'b0;
	else if ((new_task == 1'b1) && (ctrl_bus >= 16'd12) && (ctrl_bus < 16'd16))
		ram_read_flag <= 1'b1;
	else
		ram_read_flag <= 1'b0;

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		ram_read_flag_d1 <= 1'b0;
		ram_read_flag_d2 <= 1'b0;
	end
	else
	begin
		ram_read_flag_d1 <= ram_read_flag;
		ram_read_flag_d2 <= ram_read_flag_d1;
	end

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		imd_read_flag <= 1'b0;
	else if ((new_task == 1'b1) && (ctrl_bus >= 16'd16) && (ctrl_bus < 16'd20))
		imd_read_flag <= 1'b1;
	else
		imd_read_flag <= 1'b0;

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		imd_read_flag_d1 <= 1'b0;
		imd_read_flag_d2 <= 1'b0;
	end
	else
	begin
		imd_read_flag_d1 <= imd_read_flag;
		imd_read_flag_d2 <= imd_read_flag_d1;
	end

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		ALU_flag <= 1'b0;
	else if ((new_task == 1'b1) && (ctrl_bus >= 16'd20) && (ctrl_bus < 16'd24))
		ALU_flag <= 1'b1;
	else
		ALU_flag <= 1'b0;
	
always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		ALU_flag_d1 <= 1'b0;
		ALU_flag_d2 <= 1'b0;
	end
	else
	begin
		ALU_flag_d1 <= ALU_flag;
		ALU_flag_d2 <= ALU_flag_d1;
	end

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		ip_update_flag <= 1'b0;
	else if ((new_task == 1'b1) && (ctrl_bus >= 16'd24) && (ctrl_bus < 16'd28))
		ip_update_flag <= 1'b1;
	else
		ip_update_flag <= 1'b0;

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		ip_update_flag_d1 <= 1'b0;
		ip_update_flag_d2 <= 1'b1;
	end
	else
	begin
		ip_update_flag_d1 <= ip_update_flag;
		ip_update_flag_d2 <= ip_update_flag_d1;
	end

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		stop_flag <= 1'b0;
	else if ((new_task == 1'b1) && (ctrl_bus >= 16'd28) && (ctrl_bus < 16'd32))
		stop_flag <= 1'b1;
	else
		stop_flag <= 1'b0;

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		stop_flag_d1 <= 1'b0;
		stop_flag_d2 <= 1'b0;
	end
	else
	begin
		stop_flag_d1 <= stop_flag;
		stop_flag_d2 <= stop_flag_d1;
	end
	
always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		ip <= 16'h0000;
	else if (ip_update_flag == 1'b1)
	begin
		if (ctrl_bus_buf[1:0] == 2'd0)	//0号表示加上指令长度，指向下一指令。
			ip <= ip + 16'h1;		//本仿真CPU的长度为2字节。但我设置IP核时，1个单位为2字节。
		else if (ctrl_bus_buf[1:0] == 2'd1)
			ip <= ip + data_bus_buf;
		else if (ctrl_bus_buf[1:0] == 2'd2)
			ip <= data_bus_buf;
		else if (ctrl_bus_buf[1:0] == 2'd3)
			ip <= 16'h0000;
		else
			ip <= ip;
	end
	else if (exe_running == 1'b0)
		ip <= 16'h0;
	else
		ip <= ip;	

always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		ctrl_bus_represent <= 16'hz;
		addr_bus_represent <= 16'hz;
		data_bus_represent <= 16'hz;
	end
	else if (reg_write_flag == 1'b1)
	begin
		ctrl_bus_represent <= 16'h0000;
		addr_bus_represent <= 16'h0000;
		data_bus_represent <= 16'd0;
	end
	else if (reg_write_flag_d1 == 1'b1)
	begin
		ctrl_bus_represent <= 16'h0001;
		addr_bus_represent <= addr_bus_buf;  //地址总线用于缓存待写入的寄存器ID号
		data_bus_represent <= inner_reg[ctrl_bus_index];
	end
	else if (reg_read_flag == 1'b1)
	begin
		ctrl_bus_represent <= 16'h0000;
		addr_bus_represent <= 16'h0000;
		data_bus_represent <= 16'hz;
	end
	else if (reg_read_flag_d1 == 1'b1)
	begin
		ctrl_bus_represent <= 16'h0002;
		addr_bus_represent <= addr_bus_buf;  //地址总线用于缓存待读取的寄存器ID号
		data_bus_represent <= 16'hz;
	end
	else if (ram_write_flag == 1'b1)
	begin
		ctrl_bus_represent <= 16'h0000;
		addr_bus_represent <= 16'h0000;
		data_bus_represent <= 16'd0;
	end
	else if (ram_write_flag_d1 == 1'b1)
	begin
		ctrl_bus_represent <= 16'h0004;
		addr_bus_represent <= addr_bus_buf;  //地址总线用于缓存待写入的ram地址值。
		data_bus_represent <= inner_reg[ctrl_bus_index];
	end
	else if (ram_read_flag == 1'b1)
	begin
		ctrl_bus_represent <= 16'h0000;
		addr_bus_represent <= 16'h0000;
		data_bus_represent <= 16'hz;
	end
	else if (ram_read_flag_d1 == 1'b1)
	begin
		ctrl_bus_represent <= 16'h0008;
		addr_bus_represent <= addr_bus_buf;  //地址总线用于缓存待待写入的ram地址值
		data_bus_represent <= 16'hz;
	end
	
	else if (ALU_flag == 1'b1)
	begin
		ctrl_bus_represent <= 16'h0000;
		addr_bus_represent <= 16'h0000;
		data_bus_represent <= 16'hz;
	end
	else if (ALU_flag_d1 == 1'b1)
	begin
		ctrl_bus_represent <= 16'h0010;
		addr_bus_represent <= addr_bus_buf;
		data_bus_represent <= 16'hz;
	end

	else
	begin
		ctrl_bus_represent <= 16'hz;
		addr_bus_represent <= 16'hz;
		data_bus_represent <= 16'hz;
	end	


/*********************************************
	work_ok信号用于表示，控制中心的本次任务执行
完成，它并不表示已完成了某一个机器指令。一个机器
指令可以包含许多微操作。work_ok信号仅表示完成了一
个微操作。work_ok_inner是控制中心的子功能模块传
回来的信号。work_ok_inner的信号来源，可能是ALU，
可能是rw_reg，rw_ram。work_ok_inner信号来自本模
块的子功能模块，而work_ok来自本模块。
	由子功能模块处理的一些个操作，当收到了子模块
传来的work_ok_inner信号，则work_ok信号变为有效。
如果是一些个由本模块直接处理的操作任务，则根据本
模块的一些个标志变量来设置work_ok的有效时机。
	work_ok信号仅维持一个时钟的高电平，其余时间为
低电平。
**********************************************/
always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
		work_ok <= 1'b0;
	else if (work_ok_inner == 1'b1)
		work_ok <= 1'b1;
	else if (imd_read_flag_d1 == 1'b1)
		work_ok <= 1'b1;
	else if (ip_update_flag_d1 == 1'b1)
		work_ok <= 1'b1;
	else if (stop_flag_d1 == 1'b1)
		work_ok <= 1'b1;
	else
		work_ok <= 1'b0;


always @(posedge sys_clk or negedge sys_rst_n)
	if (sys_rst_n == 1'b0)
	begin
		inner_reg[0] <= 16'h0000;
		inner_reg[1] <= 16'h0000;
		inner_reg[2] <= 16'h0000;
		inner_reg[3] <= 16'h0000;
	end
	else if (work_ok_inner == 1'b1 && ctrl_bus_buf >= 16'd4
			&& ctrl_bus_buf < 16'd8)
		inner_reg[ctrl_bus_index] <= data_sig_inner;
	else if (work_ok_inner == 1'b1 && ctrl_bus_buf >= 16'd12
			&& ctrl_bus_buf < 16'd16)
		inner_reg[ctrl_bus_index] <= data_sig_inner;
	else if (imd_read_flag == 1'b1)
		inner_reg[ctrl_bus_index] <= data_bus_buf;
	else if (work_ok_inner == 1'b1 && ctrl_bus_buf >= 16'd20
			&& ctrl_bus_buf < 16'd24)
		inner_reg[ctrl_bus_index] <= data_sig_inner;
	else
	begin
		inner_reg[0] <= inner_reg[0];
		inner_reg[1] <= inner_reg[1];
		inner_reg[2] <= inner_reg[2];
		inner_reg[3] <= inner_reg[3];
	end
	
rw_reg rw_reg_inst
(
	.sys_clk(sys_clk),
	.sys_rst_n(sys_rst_n),
	
	.ctrl_sig_inner(ctrl_sig_inner),
	.addr_sig_inner(addr_sig_inner),
	.data_sig_inner(data_sig_inner),
	
	.work_ok_inner(work_ok_inner)
);

rw_ram rw_ram_inst
(
	.sys_clk(sys_clk),
	.sys_rst_n(sys_rst_n),
	
	.ctrl_sig_inner(ctrl_sig_inner),
	.addr_sig_inner(addr_sig_inner),
	.data_sig_inner(data_sig_inner),
	
	.work_ok_inner(work_ok_inner)
);

ALU ALU_inst
(
	.sys_clk(sys_clk),
	.sys_rst_n(sys_rst_n),
	.oprand0(oprand0),
	.oprand1(oprand1),
	.oprand2(oprand2),
	.ctrl_sig_inner(ctrl_sig_inner),
	.addr_sig_inner(addr_sig_inner),
	.data_sig_inner(data_sig_inner),
	.work_ok_inner(work_ok_inner)
);

instruct_unit instruct_unit_inst
(
	.sys_clk(sys_clk),
	.sys_rst_n(sys_rst_n),
	.exe_en(exe_en),
	.work_ok(work_ok),
	.op_code_receive(op_code_out),
	.reserve_bit_receive(reserve_bit_out),
	.op_rand_receive(op_rand_out),
	.ctrl_bus(ctrl_bus),
	.addr_bus(addr_bus),
	.data_bus(data_bus),
	.job_ok(job_ok)
);

endmodule